home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 23
/
Amiga Format AFCD23 (Feb 1998, Issue 107).iso
/
+look_here_1st!+
/
handy_tools
/
snoopdos
/
snoopdos_source
/
patchcode.s
< prev
next >
Wrap
Text File
|
1997-02-27
|
5KB
|
145 lines
*****************************************************************************
*
* PATCHCODE.S vi:ts=8
*
* Copyright (c) Eddy Carroll, September 1994.
*
* Patch code used by SnoopDos 3.0. This is copied into the
* patch table when we first install the SnoopDos patches.
*
*****************************************************************************
XDEF _PatchCode_Start
XDEF _PatchCode_NormalReturn
XDEF _PatchCode_JumpOrigFunc
XDEF _PatchCode_End
include "exec/execbase.i"
include "exec/tasks.i"
SECTION Text,CODE
;
; This is the entry point for the patch. It checks to see if
; the patch is currently enabled or not and if it isn't,
; jumps to the original function instead. Normally, if the
; patch isn't enabled, we will remove it completely, but if
; something has patched it after we did, we can't remove it
; so this code is needed.
;
; Note that we do a slight trick to check if the patch is enabled
; as quickly as possible. We'd like to say CMPI.W #0,enabled(pc)
; or similar, but that won't work on a 68000. So instead, we ensure
; that the enabled flag is always either $00000000 or $FFFFFFFF, and
; then check A7 (which is guaranteed to never be either value)
; against it.
;
_PatchCode_Start:
cmp.l enabled(pc),a7 ; Patch enabled?
blo.b callnewfunc ; If so, call new function
move.l origfunc(pc),-(a7) ; Else call old function
rts ;
;----------------------------------------------------------------------------
;
; Calling our new function. We do the following:
;
; - Check that we have enough stack to execute the patch.
; - Increment usage count to show someone is running the patch code
; - Call the new patch code. If the patch code decides not to monitor
; the call, it will adjust the return address on the stack to
; return to a different point.
; - Decrement usage count, and return to caller
;
; If the stack return address was adjusted, it points to code that:
;
; - Decrements the usage count
; - Jumps to the original function
;
; The reason we do it like this is so that when we are ignoring a
; particular task, any calls made by the task will return to this
; patch code rather than our C code. This allows the C code to be
; unloaded even if there are still some calls that have not yet
; returned (e.g. a RunCommand() call while booting.)
;
; WARNING: If you make any changes here that will adjust the stack
; contents on entry to the C code, you MUST update the MarkCallAddr
; and CallAddr macros in PATCHES.C accordingly. Ditto for the
; JumpOrigFunc[] macro.
;
callnewfunc:
movem.l a0/a1/d1/a5,-(a7) ; Save registers
;
; Now some stack checking code. If the A7 lies in the range
; SPLower to SPUpper for the current task, then we check if
; there's enough room left on the stack to carry out the call.
;
; If A7 doesn't seem to be on the task's stack, then it means
; the task has allocated a different stack -- it's either a
; CLI program or a SAS-compiled program that allocated a new
; stack. In either case, we assume the program has allocated
; sufficient stack space (the only things that will really cause
; a problem are tasks with very small stacks, like device drivers).
;
move.l sysbase(pc),a5 ; Get pointer to this task
move.l ThisTask(a5),a5 ;
cmp.l TC_SPUPPER(a5),a7 ; Check if A7 above upper stack bound?
bhi.s stack_okay ; If so, no point in checking further
move.l TC_SPLOWER(a5),a5 ; Get lower bound
cmp.l a5,a7 ; Check if A7 below lower stack bound?
blo.s stack_okay ; If so, no point in checking further
add.l stackneeded(pc),a5 ; Calculate space needed
cmp.l a5,a7 ; Does A7 remain within bounds?
blo.s stack_failed ; If not, skip this call
stack_okay:
lea.l usecount(pc),a5 ;
addq.w #1,(a5) ; Increment usage count
move.l newfunc(pc),a5 ;
jsr (a5) ; Call the C patch code
_PatchCode_NormalReturn:
lea.l usecount(pc),a5 ;
subq.w #1,(a5) ; Decrement usage count
movem.l (a7)+,a0/a1/d1/a5 ; Restore registers
move.l d0,d1 ; Copy D0 to D1 for compatibility
rts ; And return to caller
;
; We reach here by patching the return address directly on the stack.
; If D0 is one of the parameters to the function, then the return
; value from the function must be that parameter, so that D0 will
; be setup correctly for calling the real function.
;
_PatchCode_JumpOrigFunc:
lea.l usecount(pc),a5 ;
subq.w #1,(a5) ; Decrement usage count
stack_failed:
movem.l (a7)+,a0/a1/d1/a5 ; Restore registers
move.l origfunc(pc),-(a7) ; Jump to original function
rts ;
cnop 0,4 ; Keep remainder long word aligned
_PatchCode_End:
;
; The following fields are also defined in the C Patch structure.
; The two definitions must match exactly or Bad Things will happen.
;
; They follow the above code directly, rather than appearing in a
; separate section, because they are accessed using PC-relative
; addressing.
;
origfunc dc.l 0 ; Pointer to original function
newfunc dc.l 0 ; Pointer to our replacement code
enabled dc.l 0 ; True if enabled
sysbase dc.l 0 ; Points to ExecBase
stackneeded dc.l 0 ; #bytes free stack required
usecount dc.w 0 ; Number of callers in function
END